package com.algorithm.liyc.greedy;

/**
 * 0134.加油站
 *
 * 在一条环路上有 N 个加油站，其中第 i 个加油站有汽油 gas[i] 升。
 * 你有一辆油箱容量无限的的汽车，从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发，开始时油箱为空。
 * 如果你可以绕环路行驶一周，则返回出发时加油站的编号，否则返回 -1。
 *
 * 说明:
 * ● 如果题目有解，该答案即为唯一答案。
 * ● 输入数组均为非空数组，且长度相同。
 * ● 输入数组中的元素均为非负数。
 *
 * for循环适合模拟从头到尾的遍历，而while循环适合模拟环形遍历，要善于使用while！
 *

 * @author Liyc
 * @date 2024/1/29 15:00
 **/

public class Solution8 {

    /**
     * 直接从全局进行贪心选择，情况如下：
     * ●  情况一：如果gas的总和小于cost总和，那么无论从哪里出发，一定是跑不了一圈的
     * ●  情况二：rest[i] = gas[i]-cost[i]为一天剩下的油，i从0开始计算累加到最后一站，如果累加没有出现负数，说明从0出发，油就没有断过，那么0就是起点。
     * ●  情况三：如果累加的最小值是负数，汽车就要从非0节点出发，从后向前，看哪个节点能把这个负数填平，能把这个负数填平的节点就是出发节点。
     * @param gas
     * @param cost
     * @return
     */
    public int canCompleteCircuit1(int[] gas, int[] cost) {
        int countNum = 0;
        int  min = 0;
        for (int i = 0; i < gas.length; i++) {
            int rest = gas[i] - cost[i];
            countNum += rest;
            if (countNum < 0) {
                min = countNum;
            }
        }
        //情况1
        if (countNum < 0) return -1;
        //情况2
        if (min >= 0) return 0;
        //情况3
        for (int i = gas.length - 1; i >= 0; i--) {
            int rest = gas[i] - cost[i];
            min += rest;
            if (min >= 0) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 首先如果总油量减去总消耗大于等于零那么一定可以跑完一圈，说明 各个站点的加油站 剩油量rest[i]相加一定是大于等于零的。
     * 每个加油站的剩余量rest[i]为gas[i] - cost[i]。
     * i从0开始累加rest[i]，和记为curSum，一旦curSum小于零，说明[0, i]区间都不能作为起始位置，因为这个区间选择任何一个位置作为起点，
     * 到i这里都会断油，那么起始位置从i+1算起，再从0计算curSum。
     * @param gas
     * @param cost
     * @return
     */
    public int canCompleteCircuit2(int[] gas, int[] cost) {
        int start = 0;
        int totalNum = 0;
        int restNum = 0;
        for (int i = 0; i < gas.length; i++) {
            restNum += gas[i] - cost[i];
            totalNum += gas[i] - cost[i];
            if (restNum < 0) {// 当前累加rest[i]和 curSum一旦小于0
                start = i + 1;// 起始位置更新为i+1
                restNum = 0;// curSum从0开始
            }
        }
        if (totalNum < 0) return -1;// 说明怎么走都不可能跑一圈了

        return start;
    }
}
